//
//  dot_view.m
//  sbrush
//
//  Created by Phillip Popp on 4/30/11.
//  Copyright 2011 __MyCompanyName__. All rights reserved.
//

#import "dot_view.h"

#include "sbrush_instrument.h"
#include <vector>

using namespace sbrush;
using namespace std;

@implementation DotView

@synthesize minDotRadius;
@synthesize maxDotRadius;
@synthesize backgroundColor;
@synthesize framePeriod;
@synthesize fadePerFrame;

- (id)initWithFrame:(NSRect)frame {
    self = [super initWithFrame:frame];
    if (self) {
		_doClear = YES;
		_drawCountdown = NO;
		_countdownVal = 0;
		minDotRadius = 1.0f;
		maxDotRadius = 10.0f;
		backgroundColor = [NSColor whiteColor];
		framePeriod = 0.03f;
		fadePerFrame = 0.1f;
		_timer = nil;
    }
    return self;
}

- (void) dealloc {
	[backgroundColor release];
	[_timer release];
	[super dealloc];
}

- (BOOL) isOpaque {
	return YES;
}

- (void) startCountdown {
	_drawCountdown = YES;
}

- (void) displayCountdown:(unsigned)count {
	_countdownVal = count;
}

- (void) finishCountdown {
	_drawCountdown = NO;
	_doClear = YES;
}

- (void) startDrawing {
	if (_timer != nil) {
		[self stopDrawing];
	}
	_timer = [NSTimer timerWithTimeInterval:framePeriod
									 target:self
								   selector:@selector(redraw:)
								   userInfo:nil
									repeats:YES];
	[[NSRunLoop currentRunLoop] addTimer: _timer forMode: NSDefaultRunLoopMode];
	[super startDrawing];
}
- (void) stopDrawing {
	[super stopDrawing];
	[_timer invalidate];
	[_timer release];
	_timer = nil;
}

- (void) redraw:(NSTimer*)timer {
	[self setNeedsDisplay:YES];
}

- (void)drawRect:(NSRect)dirtyRect {
	NSRect bounds = [self bounds];
	if (_drawCountdown) {
		/* clear with white */
		[[NSColor whiteColor] setFill];
		NSRectFill(bounds);
		
		NSLog(@"countdown color %d", _countdownVal);
		switch (_countdownVal) {
			case 2:
				[[NSColor yellowColor] setFill];
				break;
			case 1:
				[[NSColor greenColor] setFill];
				break;
			default:
				[[NSColor redColor] setFill];
				break;
		}
		NSRect circleBounds;
		circleBounds.size.width = min(bounds.size.width, bounds.size.height);
		circleBounds.size.height = circleBounds.size.width;
		circleBounds.origin.x = bounds.size.width / 2.0f - 
		circleBounds.size.width / 2.0f;
		circleBounds.origin.y = bounds.size.height / 2.0f - 
		circleBounds.size.height / 2.0f;
		[[NSBezierPath bezierPathWithOvalInRect:circleBounds] fill];
	}
	else {	
		/* apply white fade here */
		if (_doClear) {
			/* clear with white */
			[[NSColor whiteColor] setFill];
			NSRectFill(bounds);
			_doClear = NO;
		} else {
			/* apply a bit of fading */
			[[[NSColor whiteColor] colorWithAlphaComponent: fadePerFrame] setFill];
			NSRectFillUsingOperation(bounds, NSCompositePlusLighter);
		}
	}
	
	const vector<const InstrumentState*>* undrawnStates = NULL;
	undrawnStates = [self acquireLatestStates];
	if (undrawnStates == NULL) {
		return;
	}
	
	NSRect brushBounds;
	for (size_t i = 0; i < undrawnStates->size(); i++) {
		const InstrumentState* state = undrawnStates->at(i);
		if (state == NULL) {
			continue;
		}
		/* ensure that we are getting the events we want to get */
		if (state->boolSize() != 2 || state->floatSize() != 6) {
			/* TODO: would be great if this were changed so that it can handle
			 * instrument states with other sizes... alas there is no time to do
			 * that now */
			continue;
		}
		/* avoid drawing proximity events */
		if (state->bools()[0] || state->bools()[1]) {
			continue;
		}
		
		/* set location of brush */
		brushBounds.origin.x = state->floats()[0] * bounds.size.width;
		brushBounds.origin.y = state->floats()[1] * bounds.size.height;
		
		/* set size of brush */
		brushBounds.size.width = (hypotf(state->floats()[4], state->floats()[5]) 
								  * minDotRadius + maxDotRadius) / 2.0f;
		brushBounds.size.height = brushBounds.size.width;
		
		/* set color */
		if (state->floats()[2] == 0.0f) {
			/* if z value is 0, use pressure for hue */
			[[NSColor colorWithCalibratedHue:(state->floats()[3])
								  saturation:1.0 
								  brightness:0.5 
									   alpha:1.0] set];
		}
		else {
			/* if z value not zero, us it for hue */
			[[NSColor colorWithCalibratedHue:(state->floats()[2])
								  saturation:((state->floats()[4] + 1.0f) / 2.0f)
								  brightness:((state->floats()[5] + 1.0f) / 2.0f)
									   alpha:1.0] set];
		}
		[[NSBezierPath bezierPathWithOvalInRect:brushBounds] fill];
	}
}

- (void) setFramePeriod:(NSTimeInterval)period {
	framePeriod = period;
	if (_timer != nil) {
		[self stopDrawing];
		[self startDrawing];
	}
}

- (void) clear {
	_doClear = YES;
}



@end
